# -*- coding: utf-8 -*-
# @Time    : 2024/6/11 11:48
# @Author  : yujiahao
# @File    : 11_set.py
# @description:python中的集合

"""
Python 集合类型及其应用场景：

1. List（列表）：
   - list：
     特性：动态数组，随机访问和插入删除效率适中。
     使用方法：append(), extend(), insert(), remove(), pop(), index(), count(), sort(), reverse()
     注意事项：线程不安全，需手动同步。
     创建方法：
       - 空列表：my_list = []
       - 带初始值的列表：my_list = [1, 2, 3, 4]
     应用场景：
       - 通用序列操作的场景：适用于存储和处理有序数据，如任务列表、学生名单。
       - 需要动态调整大小的场景：适用于需要频繁添加或删除元素的情况。
       - 需要按索引访问元素的场景：适用于需要随机访问元素的情况，如读取特定位置的元素。

2. Set（集合）：
   - set：
     特性：基于哈希表实现，不保证元素顺序。
     使用方法：add(), remove(), discard(), pop(), clear(), union(), intersection(), difference(), symmetric_difference()
     注意事项：线程不安全，需手动同步。
     创建方法：
       - 空集合：my_set = set()
       - 带初始值的集合：my_set = {1, 2, 3, 4}
     应用场景：
       - 快速查找和集合运算的场景：适用于需要快速查找元素、去重操作或集合运算（如并集、交集、差集）的情况。
       - 存储唯一元素的场景：适用于需要确保元素唯一性的情况，如存储唯一的用户ID。

3. Dict（映射）：
   - dict：
     特性：基于哈希表实现，键值对无序存储。
     使用方法：get(), keys(), values(), items(), update(), pop(), clear()
     注意事项：线程不安全，需手动同步。
     创建方法：
       - 空字典：my_dict = {}
       - 带初始值的字典：my_dict = {'a': 1, 'b': 2, 'c': 3}
     应用场景：
       - 快速查找键值对的场景：适用于需要快速查找、插入和删除键值对的情况，如实现简单的缓存、存储和查询配置项。
       - 需要键值对映射的场景：适用于需要将键映射到值的情况，如存储用户信息（键为用户ID，值为用户数据）。

4. Tuple（元组）：
   - tuple：
     特性：不可变序列，随机访问效率高。
     使用方法：count(), index()
     注意事项：不可变，一旦创建无法修改。
     创建方法：
       - 空元组：my_tuple = ()
       - 带初始值的元组：my_tuple = (1, 2, 3, 4)
     应用场景：
       - 不可变序列的场景：适用于需要存储不变数据的情况，如函数返回多个值、存储坐标点（x, y）。
       - 作为字典键的场景：由于元组是不可变的，适用于需要用作字典键的情况。
       - 需要轻量级数据结构的场景：适用于需要轻量级、不变的数据结构的情况，如数据库查询结果的存储。

这些应用场景可以帮助你更好地选择合适的集合类型来处理不同的编程任务。
"""


# 集合的创建


# ① 使用大括号创建集合
my_set = {"刘嘉玲", '关之琳', "王祖贤"}
print(my_set)

# ② 使用 set() 函数创建集合
another_set = set(["刘嘉玲", '关之琳', "王祖贤"])
print(another_set)



# 去重

'''
集合在python中是一个集合是无序,可变的数据类型,我们只用它自带的特性,其余的操作很少使用
集合在Pyhton中的关键字是set,也是以{}的形式展示 只不过集合是一个没有值得字典,为什么这么说呢??
因为集合中的元素要求是不可变的并且还是唯一的,我们就利用它是唯一来做去重
'''

lst = [1,3,4,112,23,1,3,1,41,12,3,1]
print(lst)
print(set(lst))  # 这样就没有重复的元素出现了,我们在将集合抓换成列表
list(set(lst)) # 这样就把没有重复的集合转成列表了
print(list(set(lst)))


print('''\n-----------------------------------☆☆☆分割线☆☆☆----------------------------------------\n''')

# set集合增删改查


# 增加

my_set.add('李嘉欣')
print(my_set)

# 如果已有数据则不会被添加
my_set.add('李嘉欣')
print(my_set)

# update() 方法是一个非常方便的方法，用于将多个可迭代对象的元素添加到集合中，并且可以处理不同类型的可迭代对象。它在需要合并多个数据源时特别有用。
my_set.update('宇佳豪')
print(f'会把元素迭代更新添加到原有集合当中去：{my_set}')

# 将列表中的元素添加到集合中
my_set_2 = {1, 2, 3}
my_list = [4, 5, 6]
my_set_2.update(my_list)
print(my_set_2)  # 输出: {1, 2, 3, 4, 5, 6}

# 将元组中的元素添加到集合中
my_set_2 = {1, 2, 3}
my_tuple = (4, 5, 6)
my_set_2.update(my_tuple)
print(my_set_2)  # 输出: {1, 2, 3, 4, 5, 6}


# 将字典中的键添加到集合中

my_set_2 = {1, 2, 3}
my_dict = {4: 'a', 5: 'b', 6: 'c'}
my_set_2.update(my_dict)
print(my_set_2)  # 输出: {1, 2, 3, 4, 5, 6}

# 将另一个集合中的元素添加到集合中
my_set_2 = {1, 2, 3}
another_set_2 = {4, 5, 6}
my_set_2.update(another_set_2)
print(my_set_2)  # 输出: {1, 2, 3, 4, 5, 6}


# 同时添加多个可迭代对象
my_set_2 = {1, 2, 3}
my_list = [4, 5]
my_tuple = (6, 7)
my_set_2.update(my_list, my_tuple)
print(my_set_2)  # 输出: {1, 2, 3, 4, 5, 6, 7}


print('''\n-----------------------------------☆☆☆分割线☆☆☆----------------------------------------\n''')

# 删除　　

'''
方法： 
  - pop()：移除并返回一个随机元素。如果集合为空，会引发 KeyError。
  - discard()：移除指定元素。如果元素不存在，不会引发错误。
  - remove()：移除指定元素。如果元素不存在，会引发 KeyError。
场景：
  -如果你需要移除并获取一个元素，使用 pop()。
  -如果你需要移除一个元素，并且不确定它是否在集合中，使用 discard()。
  -如果你确定要移除的元素在集合中，并且希望在元素不存在时得到一个错误提醒，使用 remove()。
 '''

s = {"刘嘉玲", '关之琳', "王祖贤","张曼⽟", "李若彤"}
item = s.pop() # 随机弹出⼀个.
print(s)
print(item)
s.remove("关之琳") # 直接删除元素
# s.remove("我不存在") # 不存在这个元素. 删除会报错
s.discard('我也不存在，但是我不会报错')
print(s)

s.clear() # 清空set集合.需要注意的是set集合如果是空的. 打印出来是set() 因为要和dict区分的.
print(s) # set()

print('''\n-----------------------------------☆☆☆分割线☆☆☆----------------------------------------\n''')

# 修改

# set集合中的数据没有索引. 也没有办法去定位⼀个元素. 所以没有办法进⾏直接修改.
# 我们可以采⽤先删除后添加的⽅式来完成修改操作
s = {"刘嘉玲", '关之琳', "王祖贤","张曼⽟", "李若彤"}
# 把刘嘉玲改成赵本⼭
s.remove("刘嘉玲")
s.add("赵本⼭")
print(s)


print('''\n-----------------------------------☆☆☆分割线☆☆☆----------------------------------------\n''')

# 查询　　
# set是⼀个可迭代对象. 所以可以进⾏for循环
for el in s:
 print(el)


print('''\n-----------------------------------☆☆☆分割线☆☆☆----------------------------------------\n''')


# 常⽤操作　　

s1 = {"张国荣", "张学友", "周星驰"}
s2 = {"张学友", "李嘉欣", "王祖贤"}

# 交集
# 两个集合中的共有元素
print(s1 & s2)
print(s1.intersection(s2))


print('''\n-----------------------------------☆☆☆分割线☆☆☆----------------------------------------\n''')

# 并集
print(s1 | s2)
print(s1.union(s2))

print('''\n-----------------------------------☆☆☆分割线☆☆☆----------------------------------------\n''')

# 差集 s1有的 s2没有的
print(s1 - s2)
print(s1.difference(s2))

print('''\n-----------------------------------☆☆☆分割线☆☆☆----------------------------------------\n''')


# 反交集   两个集合中不重复的剩余数据
print(s1 ^ s2)
print(s1.symmetric_difference(s2))


print('''\n-----------------------------------☆☆☆分割线☆☆☆----------------------------------------\n''')

s1 = {"刘能", "赵四"}
s2 = {"刘能", "赵四", "⽪⻓⼭"}

# ⼦集
print(s1 < s2) # set1是set2的⼦集吗? True
print(s1.issubset(s2))

# 超集
print(s1 > s2) # set1是set2的超集吗? False
print(s1.issuperset(s2))
# set集合本⾝是可以发⽣改变的. 是不可hash的. 我们可以使⽤frozenset来保存数据. frozenset是不可变的. 也就是⼀个可哈希的数据类型


print('''\n-----------------------------------☆☆☆分割线☆☆☆----------------------------------------\n''')

# 不可变集合 这个不是很常⽤. 了解⼀下就可以了

'''
frozenset 是 Python 中的一种不可变集合类型。与常规的 set 不同，frozenset 一旦创建就不能修改。这种不可变性使得 frozenset 可以作为其他集合（如 set）的元素或作为字典的键。

【创建 frozenset】
    你可以通过使用 frozenset() 函数来创建一个 frozenset。该函数可以接受一个可迭代对象（如列表、元组、集合等）作为参数。

【语法】  frozenset([iterable])

【特性】
    不可变：frozenset 是不可变的，这意味着一旦创建，它的内容不能被修改。你不能添加、移除或更改 frozenset 中的元素。
    可哈希：由于 frozenset 是不可变的，它是可哈希的，可以作为字典的键或作为另一个集合的元素。
'''

# 从列表创建 frozenset
fs1 = frozenset([1, 2, 3, 4, 5])
print(fs1)  # 输出: frozenset({1, 2, 3, 4, 5})

# 从集合创建 frozenset
fs2 = frozenset({1, 2, 3, 4, 5})
print(fs2)  # 输出: frozenset({1, 2, 3, 4, 5})

# 从字符串创建 frozenset
fs3 = frozenset("hello")
print(fs3)  # 输出: frozenset({'h', 'e', 'l', 'o'})

# 创建空 frozenset
fs4 = frozenset()
print(fs4)  # 输出: frozenset()

print('''\n-----------------------------------☆☆☆分割线☆☆☆----------------------------------------\n''')

# 常见操作
'''
尽管 frozenset 是不可变的，但你仍然可以执行许多集合操作，如并集、交集、差集和对称差集。这些操作不会修改原始 frozenset，而是返回一个新的 frozenset。
'''

# 并集（Union）
fs1 = frozenset([1, 2, 3])
fs2 = frozenset([3, 4, 5])
union_fs = fs1 | fs2
print(union_fs)  # 输出: frozenset({1, 2, 3, 4, 5})

# 交集（Intersection）
fs1 = frozenset([1, 2, 3])
fs2 = frozenset([3, 4, 5])
intersection_fs = fs1 & fs2
print(intersection_fs)  # 输出: frozenset({3})

# 差集（Difference）
fs1 = frozenset([1, 2, 3])
fs2 = frozenset([3, 4, 5])
difference_fs = fs1 - fs2
print(difference_fs)  # 输出: frozenset({1, 2})

# 对称差集（Symmetric Difference）
fs1 = frozenset([1, 2, 3])
fs2 = frozenset([3, 4, 5])
sym_diff_fs = fs1 ^ fs2
print(sym_diff_fs)  # 输出: frozenset({1, 2, 4, 5})

fs1 = frozenset([1, 2, 3])
fs2 = frozenset([3, 4, 5])

# 其他方法
'''
copy()：返回一个浅拷贝。
issubset()：判断是否为另一个集合的子集。
issuperset()：判断是否为另一个集合的超集。
isdisjoint()：判断两个集合是否没有交集。
'''
# 浅拷贝
fs_copy = fs1.copy()
print(fs_copy)  # 输出: frozenset({1, 2, 3})

# 子集判断
print(fs1.issubset(fs2))  # 输出: False

# 超集判断
print(fs1.issuperset({1}))  # 输出: True

# 无交集判断
print(fs1.isdisjoint(fs2))  # 输出: False

s = frozenset(["赵本⼭", "刘能", "⽪⻓⼭", "长桂"])
# 使用 frozenset 作为字典的键：
dic = {s:'123'}
print(dic)




